package com.ideaaedi.zoo.diy.artifact.flowable.convert;

import com.ideaaedi.zoo.diy.artifact.flowable.facade.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Attachment;
import org.flowable.engine.task.Comment;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.variable.api.history.HistoricVariableInstance;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * 模型转换器
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 1.0.0
 */
public final class BpmnEntityConvert {

    /**
     * {@code
     * Comment   ->   DefaultBpmnComment
     * }
     */
    public static DefaultBpmnComment convert2BpmnComment(Comment comment) {
        if (comment == null) {
            return null;
        }
        return DefaultBpmnComment.builder()
                .id(comment.getId())
                .userId(comment.getUserId())
                .dateTime(comment.getTime())
                .taskId(comment.getTaskId())
                .processInstanceId(comment.getProcessInstanceId())
                .type(comment.getType())
                .fullMessage(comment.getFullMessage())
                .build();
    }

    /**
     * {@code
     * Attachment   ->   DefaultBpmnAttachment
     * }
     */
    public static DefaultBpmnAttachment convert2BpmnAttachment(Attachment attachment) {
        if (attachment == null) {
            return null;
        }
        return DefaultBpmnAttachment.builder()
                .id(attachment.getId())
                .name(attachment.getName())
                .description(attachment.getDescription())
                .type(attachment.getType())
                .taskId(attachment.getTaskId())
                .processInstanceId(attachment.getProcessInstanceId())
                .userId(attachment.getUserId())
                .dateTime(attachment.getTime())
                .contentUrl(attachment.getUrl())
                .contentId(attachment.getContentId())
                .build();
    }

    /**
     * {@code
     * HistoricVariableInstance   ->   BpmnHisVariable
     * }
     */
    public static BpmnHisVariable convert2BpmnHisVariable(HistoricVariableInstance historicVariableInstance) {
        return DefaultBpmnHisVariable
                .builder()
                .time(historicVariableInstance.getTime())
                .id(historicVariableInstance.getId())
                .variableName(historicVariableInstance.getVariableName())
                .variableTypeName(historicVariableInstance.getVariableTypeName())
                .value(historicVariableInstance.getValue())
                .processInstanceId(historicVariableInstance.getProcessInstanceId())
                .executionId(historicVariableInstance.getExecutionId())
                .taskId(historicVariableInstance.getTaskId())
                .createTime(historicVariableInstance.getCreateTime())
                .lastUpdatedTime(historicVariableInstance.getLastUpdatedTime())
                .build();
    }

    /**
     * {@code
     * HistoricTaskInstance   ->   BpmnHisTask
     * }
     */
    public static BpmnHisTask convert2BpmnHisTask(HistoricTaskInstance historicTaskInstance) {
        return DefaultBpmnHisTask
                .builder()
                .time(historicTaskInstance.getTime())
                .id(historicTaskInstance.getId())
                .name(historicTaskInstance.getName())
                .description(historicTaskInstance.getDescription())
                .pid(historicTaskInstance.getParentTaskId())
                .category(historicTaskInstance.getCategory())
                .tenant(historicTaskInstance.getTenantId())
                .state(historicTaskInstance.getState())
                .dueDate(historicTaskInstance.getDueDate())
                .createTime(historicTaskInstance.getCreateTime())
                .owner(historicTaskInstance.getOwner())
                .assignee(historicTaskInstance.getAssignee())
                .processInstanceId(historicTaskInstance.getProcessInstanceId())
                .processDefinitionId(historicTaskInstance.getProcessDefinitionId())
                .executionId(historicTaskInstance.getExecutionId())
                .claimTime(historicTaskInstance.getClaimTime())
                .claimedBy(historicTaskInstance.getClaimedBy())
                .suspendedTime(historicTaskInstance.getSuspendedTime())
                .suspendedBy(historicTaskInstance.getSuspendedBy())
                .deleteReason(historicTaskInstance.getDeleteReason())
                .endTime(historicTaskInstance.getEndTime())
                .completedBy(historicTaskInstance.getCompletedBy())
                .durationInMillis(historicTaskInstance.getDurationInMillis())
                .workTimeInMillis(historicTaskInstance.getWorkTimeInMillis())
                .taskLocalVariables(historicTaskInstance.getTaskLocalVariables())
                .processVariables(historicTaskInstance.getProcessVariables())
                .taskDefinitionKey(historicTaskInstance.getTaskDefinitionKey())
                .formKey(historicTaskInstance.getFormKey())
                .build();
    }

    /**
     * {@code
     * HistoricProcessInstance   ->   BpmnHisProcessInstance
     * }
     */
    public static BpmnHisProcessInstance convert2BpmnHisProcessInstance(HistoricProcessInstance historicProcessInstance) {
        return DefaultBpmnHisProcessInstance
                .builder()
                .id(historicProcessInstance.getId())
                .businessKey(historicProcessInstance.getBusinessKey())
                .businessStatus(historicProcessInstance.getBusinessStatus())
                .processDefinitionId(historicProcessInstance.getProcessDefinitionId())
                .processDefinitionName(historicProcessInstance.getProcessDefinitionName())
                .processDefinitionKey(historicProcessInstance.getProcessDefinitionKey())
                .processDefinitionVersion(historicProcessInstance.getProcessDefinitionVersion())
                .processDefinitionCategory(historicProcessInstance.getProcessDefinitionCategory())
                .deploymentId(historicProcessInstance.getDeploymentId())
                .startTime(historicProcessInstance.getStartTime())
                .endTime(historicProcessInstance.getEndTime())
                .durationInMillis(historicProcessInstance.getDurationInMillis())
                .startUserId(historicProcessInstance.getStartUserId())
                .deleteReason(historicProcessInstance.getDeleteReason())
                .superProcessInstanceId(historicProcessInstance.getSuperProcessInstanceId())
                .tenant(historicProcessInstance.getTenantId())
                .name(historicProcessInstance.getName())
                .description(historicProcessInstance.getDescription())
                .processVariables(historicProcessInstance.getProcessVariables())
                .build();
    }

    /**
     * {@code
     * HistoricActivityInstance   ->   BpmnHisActivity
     * }
     */
    public static BpmnHisActivity convert2BpmnHisActivity(HistoricActivityInstance historicActivityInstance) {
        return DefaultBpmnHisActivity
                .builder()
                .time(historicActivityInstance.getTime())
                .id(historicActivityInstance.getId())
                .activityId(historicActivityInstance.getActivityId())
                .activityName(historicActivityInstance.getActivityName())
                .activityType(historicActivityInstance.getActivityType())
                .processDefinitionId(historicActivityInstance.getProcessDefinitionId())
                .processInstanceId(historicActivityInstance.getProcessInstanceId())
                .executionId(historicActivityInstance.getExecutionId())
                .taskId(historicActivityInstance.getTaskId())
                .calledProcessInstanceId(historicActivityInstance.getCalledProcessInstanceId())
                .assignee(historicActivityInstance.getAssignee())
                .startTime(historicActivityInstance.getStartTime())
                .endTime(historicActivityInstance.getEndTime())
                .durationInMillis(historicActivityInstance.getDurationInMillis())
                .transactionOrder(historicActivityInstance.getTransactionOrder())
                .deleteReason(historicActivityInstance.getDeleteReason())
                .tenant(historicActivityInstance.getTenantId())
                .build();
    }

    /**
     * {@code
     * Task   ->   DefaultBpmnTask
     * }
     */
    public static DefaultBpmnTask convert2BpmnTask(Task task) {
        if (task == null) {
            return null;
        }
        return DefaultBpmnTask.builder()
                .id(task.getId())
                .name(task.getName())
                .description(task.getDescription())
                .pid(task.getParentTaskId())
                .category(task.getCategory())
                .tenant(task.getTenantId())
                .state(task.getState())
                .dueDate(task.getDueDate())
                .createTime(task.getCreateTime())
                .owner(task.getOwner())
                .assignee(task.getAssignee())
                .processInstanceId(task.getProcessInstanceId())
                .processDefinitionId(task.getProcessDefinitionId())
                .executionId(task.getExecutionId())
                .claimTime(task.getClaimTime())
                .claimedBy(task.getClaimedBy())
                .suspendedTime(task.getSuspendedTime())
                .suspendedBy(task.getSuspendedBy())
                .taskLocalVariables(task.getTaskLocalVariables())
                .processVariables(task.getProcessVariables())
                .taskDefinitionKey(task.getTaskDefinitionKey())
                .formKey(task.getFormKey())
                .build();
    }

    /**
     * {@code
     * ProcessInstance   ->   DefaultBpmnProcessInstance
     * }
     */
    public static DefaultBpmnProcessInstance convert2BpmnProcessInstance(ProcessInstance processInstance) {
        if (processInstance == null) {
            return null;
        }
        return DefaultBpmnProcessInstance
                .builder()
                .id(processInstance.getId())
                .definitionId(processInstance.getProcessDefinitionId())
                .pid(processInstance.getParentId())
                .businessKey(processInstance.getBusinessKey())
                .businessStatus(processInstance.getBusinessStatus())
                .suspended(processInstance.isSuspended())
                .startUserId(processInstance.getStartUserId())
                .startTime(processInstance.getStartTime())
                .ended(processInstance.isEnded())
                .tenant(processInstance.getTenantId())
                .name(processInstance.getName())
                .description(processInstance.getDescription())
                .processVariables(processInstance.getProcessVariables())
                .build();
    }

    /**
     * {@code
     * ProcessDefinition   ->   DefaultBpmnProcessDefinition
     * }
     */
    public static DefaultBpmnProcessDefinition convert2BpmnProcessDefinition(ProcessDefinition processDefinition) {
        if (processDefinition == null) {
            return null;
        }
        return DefaultBpmnProcessDefinition
                .builder()
                .id(processDefinition.getId())
                .key(processDefinition.getKey())
                .name(processDefinition.getName())
                .category(processDefinition.getCategory())
                .description(processDefinition.getDescription())
                .version(processDefinition.getVersion() + "")
                .resourceName(processDefinition.getResourceName())
                .deploymentId(processDefinition.getDeploymentId())
                .tenant(processDefinition.getTenantId())
                .ifSuspended(processDefinition.isSuspended())
                .build();
    }

    /**
     * {@code
     * Deployment   ->   DefaultBpmnDeployment
     * }
     */
    public static DefaultBpmnDeployment convert2BpmnDeployment(Deployment deployment) {
        return DefaultBpmnDeployment.builder()
                .id(deployment.getId())
                .name(deployment.getName())
                .tenant(deployment.getTenantId())
                .category(deployment.getCategory())
                .deploymentTime(deployment.getDeploymentTime())
                .build();
    }

    /**
     * {@code
     * Deployment   ->   Map<String, DefaultBpmnResource>
     * }
     * <pre>
     * 注：以deploy后返回的Deployment对象作为参数 时，方法执行正常.
     *    其它场景下的Deployment对象(如查询deployment列表得到)作为
     *    参数的话，可能会因为获取不到CommandContext而出现NPE
     * </pre>
     */
    public static Map<String, DefaultBpmnResource> convert2BpmnResource(Deployment deployment) {
        return Optional.ofNullable(deployment.getResources())
                .map(map -> {
                    Map<String, DefaultBpmnResource> result = new HashMap<>(map.size());
                    map.forEach((key, value) ->
                            result.put(
                                    key,
                                    DefaultBpmnResource.builder()
                                            .id(value.getName())
                                            .name(value.getName())
                                            .bytes(value.getBytes())
                                            .build()
                            )
                    );
                    return result;
                })
                .orElse(Collections.emptyMap());
    }
}
